/*
 * uart.c
 *
 *  Created on: Aug 2, 2013
 *      Author: Ken Arok
 *
 *
 * \file
 *
 * \brief Hardware Abstraction Layer of UART Controller UC3C0512C
 *
 * Copyright (c) 2013 PT Hanindo Automation Solutions. All rights reserved.
 *
 */

#include "config_board.h"

#if BOARD_1_0_USED

#include <string.h>

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

#include "config_ROM_HW.h"
#include "board.h"
#include "sysclk.h"
#include "intc.h"
#include "spi.h"
#include "gpio.h"
#include "delay.h"
#include "rom.h"
#include "endian.h"
#include "awire.h"
#include "uart.h"

/** \name Path Name index.
 */
//! @{
#define	serCOM1		0
#define	serCOM2		1
#define	serCOM3		2
#define	serCOM4		3
#define	serCOM5		4
#define	serCOM6		5
#define	serCOM7		6
#define	serCOM8		7
#define serRS485	8
#define	serTTL		9
//!@}

/** \name Channel control for selecting port.
 */
//! @{
#define CTRL1_OFFSET				3
#define CTRL2_OFFSET				6
#define CTRL3_OFFSET				4
#define CTRL4_OFFSET				7
//! @}

/* Default baudrate. */
#ifndef UART_DEFAULT_BAUDRATE
#define UART_DEFAULT_BAUDRATE		9600
#endif

/* UART default parameter. */
#define UART_SPEED_DEFAULT				9600				// UART baudrate default is 9600
#define UART_DATA_BITS_DEFAULT			8					// UART data width default is 8 bits
#define UART_PARITY_DEFAULT				UART_NO_PARITY		// UART parity default is no parity
#define UART_STOPBIT_DEFAULT			UART_1_STOPBIT		// UART stop bit default is 1 stop bit
#define UART_CH_MODE_DEFAULT			UART_NORMAL_CHMODE	// UART channel mode default is normal


/*! \name serial UART Interrupt Request
 */
//! @{
#define serialPORT_USART1_IRQ		AVR32_USART1_IRQ
#define serialPORT_USART2_IRQ		AVR32_USART2_IRQ
#define serialPORT_USART3_IRQ		AVR32_USART3_IRQ
#define serialPORT_USART4_IRQ		AVR32_USART4_IRQ
#define serialPORT_AWIRE_IRQ		AVR32_AW_IRQ
//! @}


/* Define USART Interrupt Priority. */
#define USART_INT_PRIORITY		AVR32_INTC_INT1
#define AWIRE_INT_PRIORITY		AVR32_INTC_INT1

static spi_descriptor_t spi_uart_desc;

static const char uart_path_name[] = "COM";

static uart_peripheral_descriptors_t uart_peripheral_desc[10] =
{
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00},
	{.path_name = uart_path_name, .path_index = 16, .port_state = 0, .recved_size = NULL, .transfer_mode = 0x00}
};

/* UART option parameter. */
static uart_options_t uart_opts[10];
static awire_options_t aw_opts;

/* Keypad writing SPI characteristic options. */
static const spi_channel_options_t UART_CTRL_SPI_OPTIONS = {
	.baudrate = 4000000,	//!> 4 MHz clock frequency.
	.bits = 8,				//!> 8-bit data length.
	.delay_bs = 4,			//!> 4 x 30ns = 120ns TCES.
	.delay_bct = 2,			//!> 2 x 30ns = 60ns
	.keep_actv = 1,			//!> Drive CS logic manualy.
	.spi_mode = SPI_MODE_0,	//!> Mode 0 of SPI.
	.master_setup = true	//!> Setup in master mode.
};

/* Structure of aWire UART options. */
static const awire_options_t AW_DEFAULT_OPTIONS = {
	.mode = AWIRE_MODE_TRANSMIT,
	.baudrate = UART_DEFAULT_BAUDRATE
};


/* Structure of UART options. */
static const uart_options_t UART_DEFAULT_OPTIONS = {
	.baudrate		= UART_DEFAULT_BAUDRATE,
	.charlength		= 8,
	.paritytype		= UART_NO_PARITY,
	.stopbits		= UART_1_STOPBIT,
	.channelmode	= UART_NORMAL_CHMODE
};


/* Available COM port name. */
static const char com_port_name[][6] = {"COM1", "COM2", "COM3", "COM4", "COM5",
										"COM6", "COM7", "COM8", "RS485", "TTL"};

/* Receive timeout value in milisecond. */
static uint32_t receive_timeout[10] = {2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400};

/* Pointer to instance of UART. */
static volatile avr32_usart_t  *uart1_inst = USART1;
static volatile avr32_usart_t  *uart2_inst = USART2;
static volatile avr32_usart_t  *uart3_inst = USART3;
static volatile avr32_usart_t  *uart4_inst = USART4;
static volatile avr32_aw_t *awire_inst = AWIRE;

/* Pointer to the data byte transmit buffer. */
static const volatile uint8_t  *uart_tx1_data_byte = NULL;
static const volatile uint8_t  *uart_tx2_data_byte = NULL;
static const volatile uint8_t  *uart_tx3_data_byte = NULL;
static const volatile uint8_t  *uart_tx4_data_byte = NULL;
/* Pointer to the data word transmit buffer. */
static const volatile uint16_t  *uart_tx1_data_word = NULL;
static const volatile uint16_t  *uart_tx2_data_word = NULL;
static const volatile uint16_t  *uart_tx3_data_word = NULL;
static const volatile uint16_t  *uart_tx4_data_word = NULL;
/* Pointer to the data byte receive buffer. */
static volatile uint8_t *uart_rx1_data_byte = NULL;
static volatile uint8_t *uart_rx2_data_byte = NULL;
static volatile uint8_t *uart_rx3_data_byte = NULL;
static volatile uint8_t *uart_rx4_data_byte = NULL;
/* Pointer to the data word receive buffer. */
static volatile uint16_t *uart_rx1_data_word = NULL;
static volatile uint16_t *uart_rx2_data_word = NULL;
static volatile uint16_t *uart_rx3_data_word = NULL;
static volatile uint16_t *uart_rx4_data_word = NULL;
/* Remaining number of data to transmit. */
static volatile uint32_t uart_tx1_nb_count = 0;
static volatile uint32_t uart_tx2_nb_count = 0;
static volatile uint32_t uart_tx3_nb_count = 0;
static volatile uint32_t uart_tx4_nb_count = 0;
/* Total number of data to receive. */
static volatile uint32_t uart_rx1_nb_received = 0;
static volatile uint32_t uart_rx2_nb_received = 0;
static volatile uint32_t uart_rx3_nb_received = 0;
static volatile uint32_t uart_rx4_nb_received = 0;
/* Remaining number of data to receive. */
static volatile uint32_t uart_rx1_nb_count = 0;
static volatile uint32_t uart_rx2_nb_count = 0;
static volatile uint32_t uart_rx3_nb_count = 0;
static volatile uint32_t uart_rx4_nb_count = 0;
/* Bit length bigger than 8-bit. */
static bool datawidth1_is_bigger8bit = false;
static bool datawidth2_is_bigger8bit = false;
static bool datawidth3_is_bigger8bit = false;
static bool datawidth4_is_bigger8bit = false;

/* Signaling for transmitter receiver. */
static xSemaphoreHandle xUART1Semaphore = NULL, xUART2Semaphore = NULL;
static xSemaphoreHandle xUART3Semaphore = NULL, xUART4Semaphore = NULL;

/* Signaling to wake up higher task. */
static xSemaphoreHandle xUART1Signaling = NULL, xUART2Signaling = NULL;
static xSemaphoreHandle xUART3Signaling = NULL, xUART4Signaling = NULL;

/* UART Control Channel */
static uint8_t uart_ctrl_channel = 0x27;
/* UART default channel masking bit. */
static uint8_t uart_default_channel_mask = 0x00;

/**\brief Interrupt handling
 */
static long prvUART1_ISR_NonNakedBehaviour(void);
static long prvUART2_ISR_NonNakedBehaviour(void);
static long prvUART3_ISR_NonNakedBehaviour(void);
static long prvUART4_ISR_NonNakedBehaviour(void);
static long prvAWIRE_ISR_NonNakedBehaviour(void);

/** \brief Initialize serial UART.
 */
static void _usart1_init(void);
static void _usart2_init(void);
static void _usart3_init(void);
static void _usart4_init(void);

/** \brief Release Semaphore based on Index.
 *
 * @param _idx	Index of UART.
 */
static void uart_release_semaphore(uint8_t _idx);

/** \brief Start transmit data out to the port.
 *  @param_uart_desc				Pointer to UART peripheral descriptor.
 *  @param_ptrData					Pointer to data buffer want to be transmitted.
 *  @param_size_t					Number of byte/word to be transmitted.
 *  @param_datawidth8bitmore		true = word transfer, false = byte transfer.
 *  @retval UART_STATUS_OK			Transmit is already started.
 *  @retval UART_ERR_INVALID_ARG	Selected Port is invalid, transmit cannot be started.
 *  @retval UART_ERR_TIMEOUT		Transmission timeout.
 */
static uart_status_code_t uart_write_start(uart_peripheral_descriptors_t *_uart_desc, const void *_ptrData, uint32_t _size_t, bool _datawidth8bitmore);

/** \brief Start receive data from the port.
 *  @param_uart_desc				Pointer to UART peripheral descriptor.
 *  @param_pbuf					Pointer to receiver buffer.
 *  @param_size					Number of byte/word to be received.
 *  @param_datawidth8bitmore		true = word transfer, false = byte transfer.
 *  @retval UART_STATUS_OK			Transmit is already started.
 *  @retval UART_ERR_INVALID_ARG	Selected Port is invalid, transmit cannot be started.
 */
static uart_status_code_t uart_read_start(uart_peripheral_descriptors_t *_uart_desc, void *_pbuf, uint32_t _size_t, bool _datawidth8bitmore);



/** \brief Get access to write protected register.
 *
 * @param_uart     Base address of the USART instance.
 * @return _status_register		true = protected, false = not protected.
 */
static bool uart_get_access_protected_register(volatile avr32_usart_t *_uart);

/** \brief Set write protected register to be active.
 *
 * @param_uart     Base address of the USART instance.
 */
static void uart_set_access_protected_register(volatile avr32_usart_t *_uart);

/*! \brief Calculates a clock divider (\e CD) and a fractional part (\e FP) for
 *         the USART asynchronous modes to generate a baud rate as close as
 *         possible to the baud rate set point.
 *
 * Baud rate calculation:
 * \f$ Baudrate = \frac{SelectedClock}{Over \times (CD + \frac{FP}{8})} \f$, \e Over being 16 or 8.
 * The maximal oversampling is selected if it allows to generate a baud rate close to the set point.
 *
 * @param_uart     Base address of the USART instance.
 * @param_baudrate  Baud rate set point.
 * @param_pba_hz    USART module input clock frequency (PBA clock, Hz).
 * @return Status.
 * @retval USART_SUCCESS        Baud rate successfully initialized.
 * @retval USART_INVALID_INPUT  Baud rate set point is out of range for the given input clock frequency.
 */
static uart_status_code_t uart_set_async_baudrate(volatile avr32_usart_t *_uart, unsigned int _baudrate, unsigned long _pba_hz);

/*! \brief Sets up the USART to use the standard RS232 protocol.
 *
 * @param_uart   Base address of the USART instance.
 * @param_opt     Options needed to set up RS232 communication (see \ref usart_options_t).
 * @param_pba_hz  USART module input clock frequency (PBA clock, Hz).
 * @return Status.
 * @retval UART_STATUS_OK        Mode successfully initialized.
 * @retval UART_INVALID_ARG		 One or more of the arguments is out of valid range.
 *
 */
static uart_status_code_t uart_init_rs232(volatile avr32_usart_t *_uart, const uart_options_t *_opt, long _pba_hz);

/*! \brief Sets up the USART to use the standard RS232 protocol in RX-only mode.
 *
 * @param_uart   Base address of the USART instance.
 * @param_opt     Options needed to set up RS232 communication (see \ref usart_options_t).
 * @param_pba_hz  USART module input clock frequency (PBA clock, Hz).
 * @return Status.
 * @retval UART_STATUS_OK       Mode successfully initialized.
 * @retval UART_INVALID_ARG		One or more of the arguments is out of valid range.
 *
 */
static uart_status_code_t uart_init_rs232_rx_only(volatile avr32_usart_t *_uart, const uart_options_t *_opt, long _pba_hz);

/** \brief Set the UART receive timeout.
 *
 * @param_uart			Base address of the USART instance.
 * @param_timeout_ms	Timeout value in milisecond.
 */
static void uart_set_rx_timeout(volatile avr32_usart_t *_uart, uint32_t _timeout_ms);

/** \brief Set the UART into mode normal (RS232).
 *
 * @param_uart Base address of the USART instance.
 */
static void uart_set_mode_normal(volatile avr32_usart_t *_uart);

/** \brief Set the UART into mode RS485.
 *
 * @param_uart Base address of the USART instance.
 */
static void uart_set_mode_rs485(volatile avr32_usart_t *_uart);

/*! \brief Resets the USART and disables TX and RX.
 *
 * @param_uart   Base address of the USART instance.
 *
 * @return Status
 * @retval UART_STATUS_OK        Reset success.
 * @retval UART_INVALID_ARG		 Reset fail due to invalid instance.
 */
static uart_status_code_t uart_reset(volatile avr32_usart_t *_uart);


/** \brief Setting up UART communication.
 *
 * @param _idx	Index of UART.
 * @param _opt	Pointer to UART options parameter.
 */
static void uart_setup(uint8_t _idx, uart_options_t *_opt);

/** \brief Interrupt service routine of UART1.
 *
 * @return _xHigherPriorityTaskWoken	Flag for context switching.
 */
__attribute__((__noinline__)) static long prvUART1_ISR_NonNakedBehaviour(void)
{
	long _xHigherPriorityTaskWoken = pdFALSE;
	uint16_t _sShort;
	uint32_t _ulStatus;

	/* What caused the interrupt? */
	_ulStatus = (uart1_inst->csr & uart1_inst->imr);
	
	if(_ulStatus & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
		/* The interrupt was caused by error of Overrun, frame and parity. Reset status bit. */
		uart1_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
	}
	else if(_ulStatus & AVR32_USART_CSR_TXRDY_MASK) {
		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit? */

		/* No more word to transmit. */
		if(uart_tx1_nb_count == 0) {
			/* Finish the receive operation. */
			uart1_inst->idr = AVR32_USART_IDR_TXRDY_MASK;
		}
		else {
			/* Copy the data. */
			if(datawidth1_is_bigger8bit == true) {
				_sShort = *uart_tx1_data_word;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx1_data_word++;
			}
			else {
				_sShort = (uint16_t)*uart_tx1_data_byte;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx1_data_byte++;
			}

			/* Put the data in the Transmit Holding Register. */
			uart1_inst->thr = ((_sShort << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK);
			/* Decrease transmitted word number. */
			uart_tx1_nb_count--;
		}
	}
	else if(_ulStatus & AVR32_USART_CSR_RXRDY_MASK) {
		/* The interrupt was caused by the receiver getting data. */
		
		/* Get the data from receiver register. */
		_sShort = ((uart1_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);
		
		if(uart_rx1_nb_count > 0) {
			/* Decrease remaining number data to receive. */
			uart_rx1_nb_count--;
			if(datawidth1_is_bigger8bit == true) {
				if(uart_rx1_data_word != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx1_data_word = _sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx1_data_word++;
					/* Increase received word number. */
					uart_rx1_nb_received++;
				}
			}
			else {
				if(uart_rx1_data_byte != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx1_data_byte = (uint8_t)_sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx1_data_byte++;
					/* Increase received byte number. */
					uart_rx1_nb_received++;
				}
			}
		}
		else {
			/* Disable receive interrupt. */
			uart1_inst->idr = AVR32_USART_IDR_RXRDY_MASK;
			
			portENTER_CRITICAL();
			xSemaphoreGiveFromISR(xUART1Semaphore, &_xHigherPriorityTaskWoken);
			portEXIT_CRITICAL();
		}
	}
	else if(_ulStatus & AVR32_USART_CSR_TXEMPTY_MASK) {
		/* The interrupt was caused by transmission complete */
		uart1_inst->idr = AVR32_USART_IDR_TXEMPTY_MASK;

		portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xUART1Semaphore, &_xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();
	}
	else if(_ulStatus & AVR32_USART_CSR_TIMEOUT_MASK)
	{
		/* The interrupt was caused by receiving complete.
		Stop timeout counter until a new character is received */
		uart1_inst->cr = AVR32_USART_CR_STTTO_MASK;
		/* Disable overrun, frame, and parity check. */
		uart1_inst->idr = (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK);
		/* Disable receive timeout. */
		uart1_inst->idr = AVR32_USART_IDR_TIMEOUT_MASK;
		
		uart_rx1_data_byte = NULL;
		uart_rx1_data_word = NULL;

		portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xUART1Signaling, &_xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();
	}
	else {
		// Do nothing
	}

	/* Using data memory barriers in the IRQ handler to make sure that:
	- the request has been disasserted, and that
	- the (potential) write in the idr has been done
	... before returning from the handler */
	uart1_inst->csr;

	/* The return value will be used by portEXIT_SWITCHING_ISR() to know if it
	should perform a vTaskSwitchContext(). */
	return (_xHigherPriorityTaskWoken);
}


/** \brief Interrupt service routine of UART2.
 *
 * @return _xHigherPriorityTaskWoken	Flag for context switching.
 */
__attribute__((__noinline__)) static long prvUART2_ISR_NonNakedBehaviour(void)
{
	long _xHigherPriorityTaskWoken = pdFALSE;
	uint16_t _sShort;
	uint32_t _ulStatus;

	/* What caused the interrupt? */
	_ulStatus = (uart2_inst->csr & uart2_inst->imr);

	if(_ulStatus & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
		/* The interrupt was caused by error of Overrun, frame and parity. Reset status bit. */
		uart2_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
	}
	else if(_ulStatus & AVR32_USART_CSR_TXRDY_MASK) {
		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit? */

		/* No more word to transmit. */
		if(uart_tx2_nb_count == 0) {
			/* Finish the receive operation. */
			uart2_inst->idr = AVR32_USART_IDR_TXRDY_MASK;
		}
		else {
			/* Copy the data. */
			if(datawidth1_is_bigger8bit == true) {
				_sShort = *uart_tx2_data_word;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx2_data_word++;
			}
			else {
				_sShort = (uint16_t)*uart_tx2_data_byte;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx2_data_byte++;
			}

			/* Put the data in the Transmit Holding Register. */
			uart2_inst->thr = ((_sShort << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK);
			/* Decrease transmitted word number. */
			uart_tx2_nb_count--;
		}
	}
	else if(_ulStatus & AVR32_USART_CSR_RXRDY_MASK) {
		/* The interrupt was caused by the receiver getting data. */
		/* Get the data from receiver register. */
		_sShort = ((uart2_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);

		if(uart_rx2_nb_count > 0) {
			/* Decrease remaining number data to receive. */
			uart_rx2_nb_count--;

			if(datawidth2_is_bigger8bit == true) {
				if(uart_rx2_data_word != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx2_data_word = _sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx2_data_word++;
					/* Increase received word number. */
					uart_rx2_nb_received++;
				}
			}
			else {
				if(uart_rx2_data_byte != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx2_data_byte = (uint8_t)_sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx2_data_byte++;
					/* Increase received byte number. */
					uart_rx2_nb_received++;
				}
			}
		}
		else {
			/* Disable receive interrupt. */
			uart2_inst->idr = AVR32_USART_IDR_RXRDY_MASK;
			
			portENTER_CRITICAL();
			xSemaphoreGiveFromISR(xUART2Semaphore, &_xHigherPriorityTaskWoken);
			portEXIT_CRITICAL();
		}
	}
	else if(_ulStatus & AVR32_USART_CSR_TXEMPTY_MASK) {
		/* The interrupt was caused by transmission complete */
		uart2_inst->idr = AVR32_USART_IDR_TXEMPTY_MASK;

		/* Set RTS2 to low. See schematic. */
		uart2_inst->cr = AVR32_USART_CR_RTSEN_MASK;
			
		portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xUART2Semaphore, &_xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();
	}
	else if(_ulStatus & AVR32_USART_CSR_TIMEOUT_MASK)
	{
		/* The interrupt was caused by receiving complete.
		Stop timeout counter until a new character is received */
		uart2_inst->cr = AVR32_USART_CR_STTTO_MASK;
		/* Disable overrun, frame, and parity check. */
		uart2_inst->idr = (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK);
		/* Disable receive timeout. */
		uart2_inst->idr = AVR32_USART_IDR_TIMEOUT_MASK;
		
		uart_rx2_data_byte = NULL;
		uart_rx2_data_word = NULL;

		portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xUART2Signaling, &_xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();
	}
	else {
		// Do nothing
	}

	/* Using data memory barriers in the IRQ handler to make sure that:
	- the request has been disasserted, and that
	- the (potential) write in the idr has been done
	... before returning from the handler */
	uart2_inst->csr;

	/* The return value will be used by portEXIT_SWITCHING_ISR() to know if it
	should perform a vTaskSwitchContext(). */
	return (_xHigherPriorityTaskWoken);
}


/** \brief Interrupt service routine of AWIRE UART.
 *
 * @return _xHigherPriorityTaskWoken	Flag for context switching.
 */
__attribute__((__noinline__)) static long prvAWIRE_ISR_NonNakedBehaviour(void)
{
	long _xHigherPriorityTaskWoken = pdFALSE;
	uint16_t _sShort;
	uint32_t _ulStatus;

	/* What caused the interrupt? */
	_ulStatus = (awire_inst->sr & awire_inst->imr);

	if(_ulStatus & AWIRE_SR_READYINT_MASK) {

		/* Clear interrupt request */
		awire_inst->scr = AWIRE_SCR_READYINT_MASK;
		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit? */

		/* No more word to transmit. */
		if(uart_tx3_nb_count == 0) {
			/* Finish the receive operation. */
			awire_inst->idr = AWIRE_IDR_READYINT_MASK;

			portENTER_CRITICAL();
			xSemaphoreGiveFromISR(xUART3Semaphore, &_xHigherPriorityTaskWoken);
			portEXIT_CRITICAL();
		}
		else {
			/* Copy the data. */
			if(datawidth3_is_bigger8bit == true) {
				_sShort = *uart_tx3_data_word;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx3_data_word++;
			}
			else {
				_sShort = (uint16_t)*uart_tx3_data_byte;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx3_data_byte++;
			}

			/* Put the data in the Transmit Holding Register. */
			awire_inst->thr = ((_sShort << AWIRE_THR_TXCHR_OFFSET) & AWIRE_THR_TXCHR_MASK);
			/* Decrease transmitted word number. */
			uart_tx3_nb_count--;
		}
	}

	/* Using data memory barriers in the IRQ handler to make sure that:
	- the request has been dis asserted, and that
	- the (potential) write in the idr has been done
	... before returning from the handler */
	awire_inst->sr;

	/* The return value will be used by portEXIT_SWITCHING_ISR() to know if it
	should perform a vTaskSwitchContext(). */
	return (_xHigherPriorityTaskWoken);
}


/** \brief Interrupt service routine of UART3.
 *
 * @return _xHigherPriorityTaskWoken	Flag for context switching.
 */
__attribute__((__noinline__)) static long prvUART3_ISR_NonNakedBehaviour(void)
{
	long _xHigherPriorityTaskWoken = pdFALSE;
	uint32_t _ulStatus;
	uint32_t _sShort;

	/* What caused the interrupt? */
	_ulStatus = (uart3_inst->csr & uart3_inst->imr);

	if(_ulStatus & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
		/* The interrupt was caused by error of Overrun, frame and parity. Reset status bit. */
		uart3_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
	}
	else if(_ulStatus & AVR32_USART_CSR_RXRDY_MASK) {
		/* The interrupt was caused by the receiver getting data. */
		/* Get the data from receiver register. */
		_sShort = ((uart3_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);

		if(uart_rx3_nb_count > 0) {
			/* Decrease remaining number data to receive. */
			uart_rx3_nb_count--;

			if(datawidth3_is_bigger8bit == true) {
				if(uart_rx3_data_word != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx3_data_word = _sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx3_data_word++;
					/* Increase received word number. */
					uart_rx3_nb_received++;
				}
			}
			else {
				if(uart_rx3_data_byte != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx3_data_byte = (uint8_t)_sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx3_data_byte++;
					/* Increase received byte number. */
					uart_rx3_nb_received++;
				}
			}
		}
		else {
			/* Disable receive interrupt. */
			uart3_inst->idr = AVR32_USART_IDR_RXRDY_MASK;

			portENTER_CRITICAL();
			xSemaphoreGiveFromISR(xUART3Semaphore, &_xHigherPriorityTaskWoken);
			portEXIT_CRITICAL();
		}
	}
	else if(_ulStatus & AVR32_USART_CSR_TIMEOUT_MASK)
	{
		/* The interrupt was caused by receiving complete.
		Stop timeout counter until a new character is received */
		uart3_inst->cr = AVR32_USART_CR_STTTO_MASK;
		/* Disable overrun, frame, and parity check. */
		uart3_inst->idr = (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK);
		/* Disable receive timeout. */
		uart3_inst->idr = AVR32_USART_IDR_TIMEOUT_MASK;
		
		uart_rx3_data_byte = NULL;
		uart_rx3_data_word = NULL;

		portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xUART3Signaling, &_xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();
	}
	else {
		// Do nothing
	}

	/* Using data memory barriers in the IRQ handler to make sure that:
	- the request has been dis-asserted, and that
	- the (potential) write in the idr has been done
	... before returning from the handler */
	uart3_inst->csr;

	/* The return value will be used by portEXIT_SWITCHING_ISR() to know if it
	should perform a vTaskSwitchContext(). */
	return (_xHigherPriorityTaskWoken);
}


/** \brief Interrupt service routine of UART4.
 *
 * @return _xHigherPriorityTaskWoken	Flag for context switching.
 */
__attribute__((__noinline__)) static long prvUART4_ISR_NonNakedBehaviour(void)
{
	/* Declare the local variables. */
	long _xHigherPriorityTaskWoken = pdFALSE;
	uint16_t _sShort;
	uint32_t _ulStatus;

	/* What caused the interrupt? */
	_ulStatus = (uart4_inst->csr & uart4_inst->imr);

	if(_ulStatus & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
		/* The interrupt was caused by error of Overrun, frame and parity. Reset status bit. */
		uart4_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
	}
	else if(_ulStatus & AVR32_USART_CSR_TXRDY_MASK) {
		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit? */

		/* No more word to transmit. */
		if(uart_tx4_nb_count == 0) {
			/* Finish the receive operation. */
			uart4_inst->idr = AVR32_USART_IDR_TXRDY_MASK;
		}
		else {
			/* Copy the data. */
			if(datawidth4_is_bigger8bit == true) {
				_sShort = *uart_tx4_data_word;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx4_data_word++;
			}
			else {
				_sShort = (uint16_t)*uart_tx4_data_byte;
				/* Increase the pointer of transmitter data buffer. */
				uart_tx4_data_byte++;
			}

			/* Put the data in the Transmit Holding Register. */
			uart4_inst->thr = ((_sShort << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK);
			/* Decrease transmitted word number. */
			uart_tx4_nb_count--;
		}
	}
	else if(_ulStatus & AVR32_USART_CSR_RXRDY_MASK) {
		/* The interrupt was caused by the receiver getting data. */
		/* Get the data from receiver register. */
		_sShort = ((uart4_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);

		if(uart_rx4_nb_count > 0) {
			/* Decrease remaining number data to receive. */
			uart_rx4_nb_count--;

			if(datawidth4_is_bigger8bit == true) {
				if(uart_rx4_data_word != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx4_data_word = _sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx4_data_word++;
					/* Increase received word number. */
					uart_rx4_nb_received++;
				}
			}
			else {
				if(uart_rx4_data_byte != NULL) {
					/* Copy data to receiver buffer. */
					*uart_rx4_data_byte = (uint8_t)_sShort;
					/* Increase pointer of receiver data buffer. */
					uart_rx4_data_byte++;
					/* Increase received byte number. */
					uart_rx4_nb_received++;
				}
			}
		}
		else {
			/* Disable receive interrupt. */
			uart4_inst->idr = AVR32_USART_IDR_RXRDY_MASK;

			portENTER_CRITICAL();
			xSemaphoreGiveFromISR(xUART4Semaphore, &_xHigherPriorityTaskWoken);
			portEXIT_CRITICAL();
		}
	}
	else if(_ulStatus & AVR32_USART_CSR_TXEMPTY_MASK) {
		/* The interrupt was caused by transmission complete */
		uart4_inst->idr = AVR32_USART_IDR_TXEMPTY_MASK;

		portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xUART4Semaphore, &_xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();
	}
	else if(_ulStatus & AVR32_USART_CSR_TIMEOUT_MASK)
	{
		/* The interrupt was caused by receiving complete.
		Stop timeout counter until a new character is received */
		uart4_inst->cr = AVR32_USART_CR_STTTO_MASK;
		/* Disable overrun, frame, and parity check. */
		uart4_inst->idr = (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK);
		/* Disable receive timeout. */
		uart4_inst->idr = AVR32_USART_IDR_TIMEOUT_MASK;
		
		uart_rx4_data_byte = NULL;
		uart_rx4_data_word = NULL;

		portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xUART4Signaling, &_xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();
	}
	else {
		// Do nothing
	}

	/* Using data memory barriers in the IRQ handler to make sure that:
	- the request has been disasserted, and that
	- the (potential) write in the idr has been done
	... before returning from the handler */
	uart4_inst->csr;

	/* The return value will be used by portEXIT_SWITCHING_ISR() to know if it
	should perform a vTaskSwitchContext(). */
	return (_xHigherPriorityTaskWoken);
}



/** \brief Interrupt service routine of serial UART1.
 */
__attribute__((__naked__)) static void prvUART1_ISR(void)
{
	/* This ISR can cause a context switch, so the first statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	prvUART1_ISR_NonNakedBehaviour();

	/* Exit the ISR.  If a task was woken by either a character being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR();
}


/** \brief Interrupt service routine of serial UART2.
 */
__attribute__((__naked__)) static void prvUART2_ISR(void)
{
	/* This ISR can cause a context switch, so the first statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	prvUART2_ISR_NonNakedBehaviour();

	/* Exit the ISR.  If a task was woken by either a character being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR();
}


/** \brief Interrupt service routine of serial aWire UART.
 */
__attribute__((__naked__)) static void prvAWIRE_ISR(void)
{
	/* This ISR can cause a context switch, so the first statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	prvAWIRE_ISR_NonNakedBehaviour();

	/* Exit the ISR.  If a task was woken by either a character being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR();
}


/** \brief Interrupt service routine of serial UART3.
 */
__attribute__((__naked__)) static void prvUART3_ISR(void)
{
	/* This ISR can cause a context switch, so the first statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	prvUART3_ISR_NonNakedBehaviour();

	/* Exit the ISR.  If a task was woken by either a character being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR();
}


/** \brief Interrupt service routine of serial UART4.
 */
__attribute__((__naked__)) static void prvUART4_ISR(void)
{
	/* This ISR can cause a context switch, so the first statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	prvUART4_ISR_NonNakedBehaviour();

	/* Exit the ISR.  If a task was woken by either a character being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR();
}


static void _usart1_init(void)
{
	/* Create binary semaphore internal signaling. */
	if(xUART1Semaphore == NULL) {
		vSemaphoreCreateBinary(xUART1Semaphore);
		if(!xUART1Semaphore) while(1);
	}

	/* Create binary semaphore global signaling. */
	if(xUART1Signaling == NULL) {
		vSemaphoreCreateBinary(xUART1Signaling);
		if(!xUART1Signaling) while(1);
	}
	
	/* Idle global signaling. */
	xSemaphoreTake(xUART1Signaling, (portTickType) 20);

	portENTER_CRITICAL();
	{
		/* Reset UART. */
		uart_reset(uart1_inst);

		/* Register the USART interrupt handler to the interrupt controller and
		enable the USART interrupt. */
		INTC_register_interrupt((__int_handler)&prvUART1_ISR, serialPORT_USART1_IRQ, USART_INT_PRIORITY);

		/* Initialize USART in RS232 mode */
		uart_init_rs232(uart1_inst, &UART_DEFAULT_OPTIONS, FPBC_HZ);
	}
	portEXIT_CRITICAL();

}


/** \brief Initialize serial UART2.
 */
static void _usart2_init(void)
{
	/* Create binary semaphore internal signaling. */
	if(xUART2Semaphore == NULL) {
		vSemaphoreCreateBinary(xUART2Semaphore);
		if(!xUART2Semaphore) while(1);
	}

	/* Create binary semaphore global signaling. */
	if(xUART2Signaling == NULL) {
		vSemaphoreCreateBinary(xUART2Signaling);
		if(!xUART2Signaling) while(1);
	}

	/* Idle global signaling. */
	xSemaphoreTake(xUART2Signaling, (portTickType) 20);

	portENTER_CRITICAL();
	{
		/* Reset UART. */
		uart_reset(uart2_inst);

		/* Register the USART interrupt handler to the interrupt controller and
		enable the USART interrupt. */
		INTC_register_interrupt((__int_handler)&prvUART2_ISR, serialPORT_USART2_IRQ, USART_INT_PRIORITY);

		/* Initialize USART in RS232 mode */
		uart_init_rs232(uart2_inst, &UART_DEFAULT_OPTIONS, FPBA_HZ);

	}
	portEXIT_CRITICAL();
}


/** \brief Initialize serial UART3.
 */
static void _usart3_init(void)
{
	/* Create binary semaphore internal signaling. */
	if(xUART3Semaphore == NULL) {
		vSemaphoreCreateBinary(xUART3Semaphore);
		if(!xUART3Semaphore) while(1);
	}

	/* Create binary semaphore global signaling. */
	if(xUART3Signaling == NULL) {
		vSemaphoreCreateBinary(xUART3Signaling);
		if(!xUART3Signaling) while(1);
	}
	
	/* Idle global signaling. */
	xSemaphoreTake(xUART3Signaling, (portTickType) 20);

	portENTER_CRITICAL();
	{
		/* Reset UART. */
		uart_reset(uart3_inst);

		/* Register the USART interrupt handler to the interrupt controller and
		enable the USART interrupt. */
		INTC_register_interrupt((__int_handler)&prvUART3_ISR, serialPORT_USART3_IRQ, USART_INT_PRIORITY);
		INTC_register_interrupt((__int_handler)&prvAWIRE_ISR, serialPORT_AWIRE_IRQ, AWIRE_INT_PRIORITY);
		
		/* Initialize USART in RS232 mode */
		uart_init_rs232_rx_only(uart3_inst, &UART_DEFAULT_OPTIONS, FPBA_HZ);
		/* Initialize aWIRE */
		awire_init(awire_inst, &AW_DEFAULT_OPTIONS);
	}
	portEXIT_CRITICAL();
}


/** \brief Initialize serial UART3.
 */
static void _usart4_init(void)
{
	/* Create binary semaphore internal signaling. */
	if(xUART4Semaphore == NULL) {
		vSemaphoreCreateBinary(xUART4Semaphore);
		if(!xUART4Semaphore) while(1);
	}

	/* Create binary semaphore global signaling. */
	if(xUART4Signaling == NULL) {
		vSemaphoreCreateBinary(xUART4Signaling);
		if(!xUART4Signaling) while(1);
	}
	
	/* Idle global signaling. */
	xSemaphoreTake(xUART4Signaling, (portTickType) 20);

	portENTER_CRITICAL();
	{
		/* Reset UART. */
		uart_reset(uart4_inst);
		
		/* Register the USART interrupt handler to the interrupt controller and
		enable the USART interrupt. */
		INTC_register_interrupt((__int_handler)&prvUART4_ISR, serialPORT_USART4_IRQ, USART_INT_PRIORITY);
		
		/* Initialize USART in RS232 mode */
		uart_init_rs232(uart4_inst, &UART_DEFAULT_OPTIONS, FPBC_HZ);
		
	}
	portEXIT_CRITICAL();
}


static void uart_release_semaphore(uint8_t _idx)
{
	switch(_idx) {
		case serCOM1:
		case serCOM2:
			xSemaphoreGive(xUART1Semaphore);
		break;

		case serCOM3:
		case serCOM4:
			xSemaphoreGive(xUART3Semaphore);
		break;

		case serCOM5:
		case serCOM6:
		case serRS485:
		case serTTL:
			xSemaphoreGive(xUART2Semaphore);
		break;

		case serCOM7:
		case serCOM8:
			xSemaphoreGive(xUART4Semaphore);
		break;

		default: break;
	}
}

static uart_status_code_t uart_write_start(uart_peripheral_descriptors_t *_uart_desc, const void *_ptrData, uint32_t _size_t, bool _datawidth8bitmore)
{
	uint16_t _sShort[4];

	if((_uart_desc->path_index == serCOM1) || (_uart_desc->path_index == serCOM2)) {

		/* Get the length to be transmitted. */
		uart_tx1_nb_count = _size_t;
		/* Check data width. */
		if(_datawidth8bitmore == true) {
			/* Get the pointer of data. */
			uart_tx1_data_word = (const volatile uint16_t *)_ptrData;
		}
		else {
			/* Get the pointer of data. */
			uart_tx1_data_byte = (const volatile uint8_t *)_ptrData;
		}
		datawidth1_is_bigger8bit = _datawidth8bitmore;

		if (_uart_desc->transfer_mode & 0x01) {
			uart1_inst->ier = (AVR32_USART_IER_TXRDY_MASK | AVR32_USART_IER_TXEMPTY_MASK);
		}
		else {
			while(uart_tx1_nb_count) {
				/* Wait transmit data register ready. */
				while(!(uart1_inst->csr & AVR32_USART_CSR_TXRDY_MASK));
				
				if(datawidth1_is_bigger8bit == true) {
					/* Get data from buffer. */
					_sShort[0] = *uart_tx1_data_word;
					/* Increase Pointer data. */
					uart_tx1_data_word++;
				}
				else {
					/* Get data from buffer. */
					_sShort[0] = (uint16_t) *uart_tx1_data_byte;
					/* Increase Pointer data. */
					uart_tx1_data_byte++;
				}
				/* Decrease number word/byte counting. */
				uart_tx1_nb_count--;
				/* Send data to transmit data register. */
				uart1_inst->thr = (uint32_t)((_sShort[0] << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK);
			}
			
			/* Wait until transmission complete. */
			while(!(uart1_inst->csr & AVR32_USART_CSR_TXEMPTY_MASK));
			
			/* Release Semaphore. */
			xSemaphoreGive(xUART1Semaphore);
		}
	}
	else if((_uart_desc->path_index == serCOM3) || (_uart_desc->path_index == serCOM4)) {
		/* Get the length to be transmitted. */
		uart_tx3_nb_count = _size_t;
		/* Check data width. */
		if(_datawidth8bitmore == true) {
			/* Get the pointer of data. */
			uart_tx3_data_word = (const volatile uint16_t *)_ptrData;
		}
		else {
			/* Get the pointer of data. */
			uart_tx3_data_byte = (const volatile uint8_t *)_ptrData;
		}
		datawidth3_is_bigger8bit = _datawidth8bitmore;

		if (_uart_desc->transfer_mode & 0x01) {
			awire_inst->ier = AWIRE_IER_READYINT_MASK;
			awire_set_mode(awire_inst, &aw_opts);
		}
		else {
			while(uart_tx3_nb_count) {
				/* Wait transmit data register ready. */
				while((awire_inst->sr & AVR32_AW_SR_BUSY_MASK));
				
				if(datawidth3_is_bigger8bit == true) {
					/* Get data from buffer. */
					_sShort[2] = *uart_tx3_data_word;
					/* Increase Pointer data. */
					uart_tx3_data_word++;
				}
				else {
					/* Get data from buffer. */
					_sShort[2] = (uint16_t) *uart_tx3_data_byte;
					/* Increase Pointer data. */
					uart_tx3_data_byte++;
				}
				/* Decrease number word/byte counting. */
				uart_tx3_nb_count--;
				/* Send data to transmit data register. */
				awire_inst->thr = ((_sShort[2] << AWIRE_THR_TXCHR_OFFSET) & AWIRE_THR_TXCHR_MASK);
			}

			/* Wait until transmission complete. */
			while((awire_inst->sr & AVR32_AW_SR_BUSY_MASK));
			
			/* Release Semaphore. */
			xSemaphoreGive(xUART3Semaphore);
		}
	}
	else if((_uart_desc->path_index == serCOM5) || (_uart_desc->path_index == serCOM6) || (_uart_desc->path_index == serRS485) || (_uart_desc->path_index == serTTL)) {
		/* Get the length to be transmitted. */
		uart_tx2_nb_count = _size_t;
		/* Check data width. */
		if(_datawidth8bitmore == true) {
			/* Get the pointer of data. */
			uart_tx2_data_word = (const volatile uint16_t *)_ptrData;
		}
		else {
			/* Get the pointer of data. */
			uart_tx2_data_byte = (const volatile uint8_t *)_ptrData;
		}
		datawidth2_is_bigger8bit = _datawidth8bitmore;
		
		if(_uart_desc->path_index == serRS485) {
			/* Set mode normal RS485. */
			uart_set_mode_rs485(uart2_inst);
			/* Set RTS2 to high. See schematic. */
			uart2_inst->cr = AVR32_USART_CR_RTSDIS_MASK;
		}
		else {
			/* Set mode normal. */
			uart_set_mode_normal(uart2_inst);
		}
		
		if (_uart_desc->transfer_mode & 0x01) {
			uart2_inst->ier = (AVR32_USART_IER_TXRDY_MASK | AVR32_USART_IER_TXEMPTY_MASK);
		}
		else {
			while(uart_tx2_nb_count) {
				/* Wait transmit data register ready. */
				while(!(uart2_inst->csr & AVR32_USART_CSR_TXRDY_MASK));
				
				if(datawidth2_is_bigger8bit == true) {
					/* Get data from buffer. */
					_sShort[1] = *uart_tx2_data_word;
					/* Increase Pointer data. */
					uart_tx2_data_word++;
				}
				else {
					/* Get data from buffer. */
					_sShort[1] = (uint16_t) *uart_tx2_data_byte;
					/* Increase Pointer data. */
					uart_tx2_data_byte++;
				}
				/* Decrease number word/byte counting. */
				uart_tx2_nb_count--;
				/* Send data to transmit data register. */
				uart2_inst->thr = (uint32_t)((_sShort[1] << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK);
			}

			/* Wait until transmission complete. */
			while(!(uart2_inst->csr & AVR32_USART_CSR_TXEMPTY_MASK));
			
			if (_uart_desc->path_index == serRS485) {
				/* Set RTS2 to low. See schematic. */
				uart2_inst->cr = AVR32_USART_CR_RTSEN_MASK;			
			}
				
			/* Release Semaphore. */
			xSemaphoreGive(xUART2Semaphore);
		}
	}
	else if((_uart_desc->path_index == serCOM7) || (_uart_desc->path_index == serCOM8)) {
		/* Get the length to be transmitted. */
		uart_tx4_nb_count = _size_t;
		/* Check data width. */
		if(_datawidth8bitmore == true) {
			/* Get the pointer of data. */
			uart_tx4_data_word = (const volatile uint16_t *)_ptrData;
		}
		else {
			/* Get the pointer of data. */
			uart_tx4_data_byte = (const volatile uint8_t *)_ptrData;
		}
		datawidth4_is_bigger8bit = _datawidth8bitmore;

		if (_uart_desc->transfer_mode & 0x01) {
			uart4_inst->ier = (AVR32_USART_IER_TXRDY_MASK | AVR32_USART_IER_TXEMPTY_MASK);
		}
		else {
			while(uart_tx4_nb_count) {
				/* Wait transmit data register ready. */
				while(!(uart4_inst->csr & AVR32_USART_CSR_TXRDY_MASK));

				if(datawidth4_is_bigger8bit == true) {
					/* Get data from buffer. */
					_sShort[3] = *uart_tx4_data_word;
					/* Increase Pointer data. */
					uart_tx4_data_word++;
				}
				else {
					/* Get data from buffer. */
					_sShort[3] = (uint16_t) *uart_tx4_data_byte;
					/* Increase Pointer data. */
					uart_tx4_data_byte++;
				}
				/* Decrease number word/byte counting. */
				uart_tx4_nb_count--;
				/* Send data to transmit data register. */
				uart4_inst->thr = (uint32_t)((_sShort[3] << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK);
			}

			/* Wait until transmission complete. */
			while(!(uart4_inst->csr & AVR32_USART_CSR_TXEMPTY_MASK));
					
			/* Release Semaphore. */
			xSemaphoreGive(xUART4Semaphore);
		}
	}
	else {
		return UART_ERR_INVALID_ARG;
	}

	return UART_STATUS_OK;
}


static uart_status_code_t uart_read_start(uart_peripheral_descriptors_t *_uart_desc, void *_pbuf, uint32_t _size_t, bool _datawidth8bitmore)
{
	uint16_t _sShort[4];
	uint32_t _imr_mask[4],_reload[4], _timeout[4];
	void *_ptrCopy1, *_ptrCopy2, *_ptrCopy3, *_ptrCopy4;

	if((_uart_desc->path_index == serCOM1) || (_uart_desc->path_index == serCOM2)) {

		/* Prevent warning. */
		_sShort[0] = 0xFFFF;
		_timeout[0] = 1;
		_reload[0] = 1;

		/* Copy Interrupt Mask Register. */
		_imr_mask[0] = uart1_inst->ier;

		if(_datawidth8bitmore == true) {
			/* Copy the current receiving pointer. */
			_ptrCopy1 = (void *)uart_rx1_data_word;
			/* Update receiving buffer */
			uart_rx1_data_word = (volatile uint16_t *)_pbuf;
		}
		else {
			/* Copy the current receiving pointer. */
			_ptrCopy1 = (void *)uart_rx1_data_byte;
			/* Update receiving buffer */
			uart_rx1_data_byte = (volatile uint8_t *)_pbuf;
		}
		uart_rx1_nb_received = 0;
		_uart_desc->recved_size = (uint32_t *)&uart_rx1_nb_received;
		uart_rx1_nb_count = _size_t;
		datawidth1_is_bigger8bit = _datawidth8bitmore;
		
		/* Set mode normal. */
		uart_set_mode_normal(uart1_inst);
		
		if (_uart_desc->transfer_mode & 0x02) {
			/* Set receiver timeout. */
			uart_set_rx_timeout(uart1_inst, receive_timeout[_uart_desc->path_index]);

			/* Enable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart1_inst->ier = (AVR32_USART_IER_RXRDY_MASK | AVR32_USART_IER_TIMEOUT_MASK |
								AVR32_USART_IER_OVRE_MASK | AVR32_USART_IER_FRAME_MASK | AVR32_USART_IER_PARE_MASK);
		}
		else {
			/* Disable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart1_inst->idr = (AVR32_USART_IDR_RXRDY_MASK | AVR32_USART_IDR_TIMEOUT_MASK |
								AVR32_USART_IDR_OVRE_MASK | AVR32_USART_IDR_FRAME_MASK | AVR32_USART_IDR_PARE_MASK);

			/* Clear receiving register and status bit register. */
			uart1_inst->rhr;
			uart1_inst->cr = AVR32_USART_CR_RSTSTA_MASK;

			_reload[0] = ((receive_timeout[_uart_desc->path_index] * 1000) / uart_opts[_uart_desc->path_index].baudrate) + 1;
			_reload[0] = _reload[0] * 3300;
			_timeout[0] = _reload[0];
			while(uart_rx1_nb_count && _timeout[0]) {
				/* Wait incoming character. Do not block peripheral. */
				_timeout[0] = _reload[0];
				while(!(uart1_inst->csr & AVR32_USART_CSR_RXRDY_MASK) && _timeout[0]) {
					_timeout[0]--;
				}

				if (_timeout[0]) {
					/* Check error receiving. */
					if(uart1_inst->csr & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
						/* Reset status bit register. */
						uart1_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
					}
					else {
						/* Get the data from receiver register. */
						_sShort[0] = ((uart1_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);

						/* Decrease remaining number data to receive. */
						uart_rx1_nb_count--;

						if(datawidth1_is_bigger8bit == true) {
							if(uart_rx1_data_word != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx1_data_word = _sShort[0];
								/* Increase pointer of receiver data buffer. */
								uart_rx1_data_word++;
								/* Increase received word number. */
								uart_rx1_nb_received++;
							}
						}
						else {
							if(uart_rx1_data_byte != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx1_data_byte = (uint8_t)_sShort[0];
								/* Increase pointer of receiver data buffer. */
								uart_rx1_data_byte++;
								/* Increase received byte number. */
								uart_rx1_nb_received++;
							}
						}
					}
				}
			}
			
			uart_rx1_data_byte = (volatile uint8_t *)_ptrCopy1;
			uart_rx1_data_word = (volatile uint16_t *)_ptrCopy1;
			uart1_inst->ier = _imr_mask[0];

			/* Release semaphore. */
			xSemaphoreGive(xUART1Semaphore);
		}
	}
	else if((_uart_desc->path_index == serCOM3) || (_uart_desc->path_index == serCOM4)) {

		/* Prevent warning. */
		_sShort[2] = 0xFFFF;
		_timeout[2] = 1;
		_reload[2] = 1;

		/* Copy Interrupt Mask Register. */
		_imr_mask[2] = uart3_inst->ier;

		if(_datawidth8bitmore == true) {
			/* Copy the current receiving pointer. */
			_ptrCopy3 = (void *)uart_rx3_data_word;
			/* Update receiving buffer */
			uart_rx3_data_word = (volatile uint16_t *)_pbuf;
		}
		else {
			/* Copy the current receiving pointer. */
			_ptrCopy3 = (void *)uart_rx3_data_byte;
			/* Update receiving buffer */
			uart_rx3_data_byte = (volatile uint8_t *)_pbuf;
		}
		uart_rx3_nb_received = 0;
		_uart_desc->recved_size = (uint32_t *)&uart_rx3_nb_received;
		uart_rx3_nb_count = _size_t;
		datawidth3_is_bigger8bit = _datawidth8bitmore;

		/* Set mode normal. */
		uart_set_mode_normal(uart3_inst);
		
		/* Set receiver timeout. */
		uart_set_rx_timeout(uart3_inst, receive_timeout[_uart_desc->path_index]);
		
		if (_uart_desc->transfer_mode & 0x02) {
			/* Enable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart3_inst->ier = (AVR32_USART_IER_RXRDY_MASK | AVR32_USART_IER_TIMEOUT_MASK |
								AVR32_USART_IER_OVRE_MASK | AVR32_USART_IER_FRAME_MASK | AVR32_USART_IER_PARE_MASK);
		}
		else {
			/* Disable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart3_inst->idr = (AVR32_USART_IDR_RXRDY_MASK | AVR32_USART_IDR_TIMEOUT_MASK |
								AVR32_USART_IDR_OVRE_MASK | AVR32_USART_IDR_FRAME_MASK | AVR32_USART_IDR_PARE_MASK);

			/* Clear receiving register and status bit register. */
			uart3_inst->rhr;
			uart3_inst->cr = AVR32_USART_CR_RSTSTA_MASK;

			_reload[2] = ((receive_timeout[_uart_desc->path_index] * 1000) / uart_opts[_uart_desc->path_index].baudrate) + 1;
			_reload[2] = _reload[2] * 3300;
			_timeout[2] = _reload[2];
			while(uart_rx3_nb_count && _timeout[2]) {
				/* Wait incoming character. Do not block peripheral. */
				_timeout[2] = _reload[2];
				while(!(uart3_inst->csr & AVR32_USART_CSR_RXRDY_MASK) && _timeout[2]) {
					_timeout[2]--;
				}

				if (_timeout[2]) {
					/* Check error receiving. */
					if(uart3_inst->csr & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
						/* Reset status bit register. */
						uart3_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
					}
					else {
						/* Get the data from receiver register. */
						_sShort[2] = ((uart3_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);

						/* Decrease remaining number data to receive. */
						uart_rx3_nb_count--;

						if(datawidth3_is_bigger8bit == true) {
							if(uart_rx3_data_word != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx3_data_word = _sShort[2];
								/* Increase pointer of receiver data buffer. */
								uart_rx3_data_word++;
								/* Increase received word number. */
								uart_rx3_nb_received++;
							}
						}
						else {
							if(uart_rx3_data_byte != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx3_data_byte = (uint8_t)_sShort[2];
								/* Increase pointer of receiver data buffer. */
								uart_rx3_data_byte++;
								/* Increase received byte number. */
								uart_rx3_nb_received++;
							}
						}
					}
				}
			}
			
			uart_rx3_data_byte = (volatile uint8_t *)_ptrCopy3;
			uart_rx3_data_word = (volatile uint16_t *)_ptrCopy3;
			uart3_inst->ier = _imr_mask[2];

			/* Release semaphore. */
			xSemaphoreGive(xUART3Semaphore);
		}
	}
	else if((_uart_desc->path_index == serCOM5) || (_uart_desc->path_index == serCOM6) || (_uart_desc->path_index == serRS485) || (_uart_desc->path_index == serTTL)) {
		/* Prevent warning. */
		_sShort[1] = 0xFFFF;
		_timeout[1] = 1;
		_reload[1] = 1;

		/* Copy Interrupt Mask Register. */
		_imr_mask[1] = uart2_inst->ier;

		if(_datawidth8bitmore == true) {
			/* Copy the current receiving pointer. */
			_ptrCopy2 = (void *)uart_rx2_data_word;
			/* Update receiving buffer */
			uart_rx2_data_word = (volatile uint16_t *)_pbuf;
		}
		else {
			/* Copy the current receiving pointer. */
			_ptrCopy2 = (void *)uart_rx2_data_byte;
			/* Update receiving buffer */
			uart_rx2_data_byte = (volatile uint8_t *)_pbuf;
		}
		uart_rx2_nb_received = 0;
		_uart_desc->recved_size = (uint32_t *)&uart_rx2_nb_received;
		uart_rx2_nb_count = _size_t;
		datawidth2_is_bigger8bit = _datawidth8bitmore;

		if(_uart_desc->path_index == serRS485) {
			/* Set mode normal RS485. */
			uart_set_mode_rs485(uart2_inst);
			/* Set RTS2 to low. See schematic. */
			uart2_inst->cr = AVR32_USART_CR_RTSEN_MASK;
		}
		else {
			/* Set mode normal. */
			uart_set_mode_normal(uart2_inst);

			if((_uart_desc->path_index == serCOM5) || (_uart_desc->path_index == serTTL)) {
				/* RTS2 must be high. See schematic. */
				uart2_inst->cr = AVR32_USART_CR_RTSDIS_MASK;
			}
		}

		/* Set receiver timeout. */
		uart_set_rx_timeout(uart2_inst, receive_timeout[_uart_desc->path_index]);

		if (_uart_desc->transfer_mode & 0x02) {
			/* Enable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart2_inst->ier = (AVR32_USART_IER_RXRDY_MASK | AVR32_USART_IER_TIMEOUT_MASK |
								AVR32_USART_IER_OVRE_MASK | AVR32_USART_IER_FRAME_MASK | AVR32_USART_IER_PARE_MASK);
		}
		else {
			/* Disable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart2_inst->idr = (AVR32_USART_IDR_RXRDY_MASK | AVR32_USART_IDR_TIMEOUT_MASK |
								AVR32_USART_IDR_OVRE_MASK | AVR32_USART_IDR_FRAME_MASK | AVR32_USART_IDR_PARE_MASK);

			/* Clear receiving register and status bit register. */
			uart2_inst->rhr;
			uart2_inst->cr = AVR32_USART_CR_RSTSTA_MASK;

			_reload[1] = ((receive_timeout[_uart_desc->path_index] * 1000) / uart_opts[_uart_desc->path_index].baudrate) + 1;
			_reload[1] = _reload[1] * 3300;
			_timeout[1] = _reload[1];
			while(uart_rx2_nb_count && _timeout[1]) {
				/* Wait incoming character. Do not block peripheral. */
				_timeout[1] = _reload[1];
				while(!(uart2_inst->csr & AVR32_USART_CSR_RXRDY_MASK) && _timeout[1]) {
					_timeout[1]--;
				}

				if (_timeout[1]) {
					/* Check error receiving. */
					if(uart2_inst->csr & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
						/* Reset status bit register. */
						uart2_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
					}
					else {
						/* Get the data from receiver register. */
						_sShort[1] = ((uart2_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);

						/* Decrease remaining number data to receive. */
						uart_rx2_nb_count--;

						if(datawidth2_is_bigger8bit == true) {
							if(uart_rx2_data_word != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx2_data_word = _sShort[1];
								/* Increase pointer of receiver data buffer. */
								uart_rx2_data_word++;
								/* Increase received word number. */
								uart_rx2_nb_received++;
							}
						}
						else {
							if(uart_rx2_data_byte != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx2_data_byte = (uint8_t)_sShort[1];
								/* Increase pointer of receiver data buffer. */
								uart_rx2_data_byte++;
								/* Increase received byte number. */
								uart_rx2_nb_received++;
							}
						}
					}
				}
			}

			uart_rx2_data_byte = (volatile uint8_t *)_ptrCopy2;
			uart_rx2_data_word = (volatile uint16_t *)_ptrCopy2;
			uart2_inst->ier = _imr_mask[1];

			/* Release semaphore. */
			xSemaphoreGive(xUART2Semaphore);
		}
		
		if((_uart_desc->path_index == serCOM5) || (_uart_desc->path_index == serTTL)) {
			/* Set RTS2 to low. See schematic. */
			uart2_inst->cr = AVR32_USART_CR_RTSEN_MASK;
		}
			
	}
	else if((_uart_desc->path_index == serCOM7) || (_uart_desc->path_index == serCOM8)) {
		/* Prevent warning. */
		_sShort[3] = 0xFFFF;
		_timeout[3] = 1;
		_reload[3] = 1;

		/* Copy Interrupt Mask Register. */
		_imr_mask[3] = uart4_inst->ier;

		if(_datawidth8bitmore == true) {
			/* Copy the current receiving pointer. */
			_ptrCopy4 = (void *)uart_rx4_data_word;
			/* Update receiving buffer */
			uart_rx4_data_word = (volatile uint16_t *)_pbuf;
		}
		else {
			/* Copy the current receiving pointer. */
			_ptrCopy4 = (void *)uart_rx4_data_byte;
			/* Update receiving buffer */
			uart_rx4_data_byte = (volatile uint8_t *)_pbuf;
		}
		uart_rx4_nb_received = 0;
		_uart_desc->recved_size = (uint32_t *)&uart_rx4_nb_received;
		uart_rx4_nb_count = _size_t;
		datawidth4_is_bigger8bit = _datawidth8bitmore;

		/* Set mode normal. */
		uart_set_mode_normal(uart4_inst);
		
		if (_uart_desc->transfer_mode & 0x02) {
			/* Set receiver timeout. */
			uart_set_rx_timeout(uart4_inst, receive_timeout[_uart_desc->path_index]);

			/* Enable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart4_inst->ier = (AVR32_USART_IER_RXRDY_MASK | AVR32_USART_IER_TIMEOUT_MASK |
								AVR32_USART_IER_OVRE_MASK | AVR32_USART_IER_FRAME_MASK | AVR32_USART_IER_PARE_MASK);
		}
		else {
			/* Disable interrupt of receiving, timeout, overrun, frame error, and parity error. */
			uart4_inst->idr = (AVR32_USART_IDR_RXRDY_MASK | AVR32_USART_IDR_TIMEOUT_MASK |
								AVR32_USART_IDR_OVRE_MASK | AVR32_USART_IDR_FRAME_MASK | AVR32_USART_IDR_PARE_MASK);

			/* Clear receiving register and status bit register. */
			uart4_inst->rhr;
			uart4_inst->cr = AVR32_USART_CR_RSTSTA_MASK;

			_reload[3] = ((receive_timeout[_uart_desc->path_index] * 1000) / uart_opts[_uart_desc->path_index].baudrate) + 1;
			_reload[3] = _reload[3] * 3300;
			_timeout[3] = _reload[3];
			while(uart_rx4_nb_count && _timeout[3]) {
				/* Wait incoming character. Do not block peripheral. */
				_timeout[3] = _reload[3];
				while(!(uart4_inst->csr & AVR32_USART_CSR_RXRDY_MASK) && _timeout[3]) {
					_timeout[3]--;
				}

				if (_timeout[3]) {
					/* Check error receiving. */
					if(uart4_inst->csr & (AVR32_USART_CSR_OVRE_MASK | AVR32_USART_CSR_FRAME_MASK | AVR32_USART_CSR_PARE_MASK)) {
						/* Reset status bit register. */
						uart4_inst->cr = AVR32_USART_CR_RSTSTA_MASK;
					}
					else {
						/* Get the data from receiver register. */
						_sShort[3] = ((uart4_inst->rhr & AVR32_USART_RHR_RXCHR_MASK) >> AVR32_USART_RHR_RXCHR_OFFSET);

						/* Decrease remaining number data to receive. */
						uart_rx4_nb_count--;

						if(datawidth4_is_bigger8bit == true) {
							if(uart_rx4_data_word != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx4_data_word = _sShort[3];
								/* Increase pointer of receiver data buffer. */
								uart_rx4_data_word++;
								/* Increase received word number. */
								uart_rx4_nb_received++;
							}
						}
						else {
							if(uart_rx4_data_byte != NULL) {
								/* Copy data to receiver buffer. */
								*uart_rx4_data_byte = (uint8_t)_sShort[3];
								/* Increase pointer of receiver data buffer. */
								uart_rx4_data_byte++;
								/* Increase received byte number. */
								uart_rx4_nb_received++;
							}
						}
					}
				}
			}
			
			uart_rx4_data_byte = (volatile uint8_t *)_ptrCopy4;
			uart_rx4_data_word = (volatile uint16_t *)_ptrCopy4;
			uart4_inst->ier = _imr_mask[3];

			/* Release semaphore. */
			xSemaphoreGive(xUART4Semaphore);
		}
	}
	else {
		return UART_ERR_INVALID_ARG;
	}

	return UART_STATUS_OK;
}


static bool uart_get_access_protected_register(volatile avr32_usart_t *_uart)
{	
	/* Get the access register if it is protected. */
	if(_uart->wpmr & AVR32_USART_WPMR_WPEN_MASK) {
		_uart->wpmr = (0x55534100 & AVR32_USART_WPMR_WPKEY_MASK);
		
		return true;
	}
	else {
		return false;
	}
}


static void uart_set_access_protected_register(volatile avr32_usart_t *_uart)
{
	_uart->wpmr = (0x55534100 | AVR32_USART_WPMR_WPEN_MASK);
}


static uart_status_code_t uart_set_async_baudrate(volatile avr32_usart_t *_uart, unsigned int _baudrate, unsigned long _pba_hz)
{
	bool _wpen;
	unsigned int _over = (_pba_hz >= 16 * _baudrate) ? 16 : 8;
	unsigned int _cd_fp = ((1 << AVR32_USART_BRGR_FP_SIZE) * _pba_hz + (_over * _baudrate) / 2) / (_over * _baudrate);
	unsigned int _cd = _cd_fp >> AVR32_USART_BRGR_FP_SIZE;
	unsigned int _fp = _cd_fp & ((1 << AVR32_USART_BRGR_FP_SIZE) - 1);

	if(_uart == NULL) return UART_ERR_INVALID_ARG;

	if (_cd < 1 || _cd > (1 << AVR32_USART_BRGR_CD_SIZE) - 1)
    return UART_ERR_INVALID_ARG;
	
	/* Get access control of protected register. */
	_wpen = uart_get_access_protected_register(_uart);
	
	_uart->mr = (_uart->mr & ~(AVR32_USART_MR_USCLKS_MASK | AVR32_USART_MR_SYNC_MASK | AVR32_USART_MR_OVER_MASK)) |
				(AVR32_USART_MR_USCLKS_MCK << AVR32_USART_MR_USCLKS_OFFSET) |
				((_over == 16) ? AVR32_USART_MR_OVER_X16 : AVR32_USART_MR_OVER_X8) << AVR32_USART_MR_OVER_OFFSET;

	_uart->brgr = _cd << AVR32_USART_BRGR_CD_OFFSET | _fp << AVR32_USART_BRGR_FP_OFFSET;
	
	/* Set protected register to previous value. */
	if(_wpen == true) {
		uart_set_access_protected_register(_uart);
	}
	
	return UART_STATUS_OK;
}


static uart_status_code_t uart_init_rs232(volatile avr32_usart_t *_uart, const uart_options_t *_opt, long _pba_hz)
{
	bool _wpen;
	
	if(_uart == NULL || _opt == NULL) return UART_ERR_INVALID_ARG;

	/* Reset the USART and shutdown TX and RX. */
	uart_reset(_uart);

	/* Check input values. */
	if (!_opt || // Null pointer.
		_opt->charlength < 5 || _opt->charlength > 9 ||
		_opt->paritytype > 7 ||
		_opt->stopbits > 2 + 255 ||
		_opt->channelmode > 3 ||
		uart_set_async_baudrate(_uart, _opt->baudrate, _pba_hz) == UART_ERR_INVALID_ARG)

		return UART_ERR_INVALID_ARG;
		
		/* Get access control of protected register. */
		_wpen = uart_get_access_protected_register(_uart);

		if (_opt->charlength == 9)
		{
			/* Character length set to 9 bits. MODE9 dominates CHRL. */
			_uart->mr |= AVR32_USART_MR_MODE9_MASK;
		}
		else
		{
			/* CHRL gives the character length (- 5) when MODE9 = 0. */
			_uart->mr |= (_opt->charlength - 5) << AVR32_USART_MR_CHRL_OFFSET;
		}

		_uart->mr |= (_opt->paritytype << AVR32_USART_MR_PAR_OFFSET) | (_opt->channelmode << AVR32_USART_MR_CHMODE_OFFSET);

		if (_opt->stopbits > UART_2_STOPBITS)
		{
			/* Set two stop bits. */
			_uart->mr |= AVR32_USART_MR_NBSTOP_2 << AVR32_USART_MR_NBSTOP_OFFSET;
			/* and a timeguard period gives the rest. */
			_uart->ttgr = _opt->stopbits - UART_2_STOPBITS + UART_DEFAULT_TIMEGUARD;
		}
		else {
			/* Insert 1, 1.5 or 2 stop bits. */
			_uart->mr |= _opt->stopbits << AVR32_USART_MR_NBSTOP_OFFSET;
			/* Give time guard */
			_uart->ttgr = UART_DEFAULT_TIMEGUARD;
		}

	/* Set receive timeout default 250ms */
	_uart->rtor = _opt->baudrate / 4;

	/* Set normal mode. */
	_uart->mr = (_uart->mr & ~AVR32_USART_MR_MODE_MASK) | (AVR32_USART_MR_MODE_NORMAL << AVR32_USART_MR_MODE_OFFSET);

	/* Set protected register to previous value. */
	if(_wpen == true) {
		uart_set_access_protected_register(_uart);
	}

	/* Enable USART interrupt sources (but not Tx for now). */
	_uart->ier = AVR32_USART_IER_RXRDY_MASK | AVR32_USART_IER_TIMEOUT_MASK;

	/* Setup complete; enable communication.
	 Enable input and output. */
	_uart->cr = AVR32_USART_CR_RXEN_MASK | AVR32_USART_CR_TXEN_MASK;

	return UART_STATUS_OK;
}


static uart_status_code_t uart_init_rs232_rx_only(volatile avr32_usart_t *_uart, const uart_options_t *_opt, long _pba_hz)
{
	bool _wpen;
	
	if(_uart == NULL || _opt == NULL) return UART_ERR_INVALID_ARG;

	/* Reset the USART and shutdown TX and RX. */
	uart_reset(_uart);

	/* Check input values. */
	if (!_opt || // Null pointer.
		_opt->charlength < 5 || _opt->charlength > 9 ||
		_opt->paritytype > 7 ||
		_opt->stopbits == 1 || _opt->stopbits > 2 + 255 ||
		_opt->channelmode > 3 ||
		uart_set_async_baudrate(_uart, _opt->baudrate, _pba_hz) == UART_ERR_INVALID_ARG)

	return UART_ERR_INVALID_ARG;

	/* Get access control of protected register. */
	_wpen = uart_get_access_protected_register(_uart);

	if (_opt->charlength == 9)
	{
		/* Character length set to 9 bits. MODE9 dominates CHRL. */
		_uart->mr |= AVR32_USART_MR_MODE9_MASK;
	}
	else
	{
		/* CHRL gives the character length (- 5) when MODE9 = 0. */
		_uart->mr |= (_opt->charlength - 5) << AVR32_USART_MR_CHRL_OFFSET;
	}

	_uart->mr |= (_opt->paritytype << AVR32_USART_MR_PAR_OFFSET) | (_opt->channelmode << AVR32_USART_MR_CHMODE_OFFSET);

	if (_opt->stopbits > UART_2_STOPBITS)
	{
		/* Set two stop bits. */
		_uart->mr |= AVR32_USART_MR_NBSTOP_2 << AVR32_USART_MR_NBSTOP_OFFSET;
		/* and a timeguard period gives the rest. */
		_uart->ttgr = _opt->stopbits - UART_2_STOPBITS + UART_DEFAULT_TIMEGUARD;
	}
	else {
		/* Insert 1 or 2 stop bits. */
		_uart->mr |= _opt->stopbits << AVR32_USART_MR_NBSTOP_OFFSET;
		/* Give time guard. */
		_uart->ttgr = UART_DEFAULT_TIMEGUARD;
	}

	/* Set receive timeout default 250ms. */
	_uart->rtor = _opt->baudrate / 4;

	/* Set normal mode. */
	_uart->mr = (_uart->mr & ~AVR32_USART_MR_MODE_MASK) | (AVR32_USART_MR_MODE_NORMAL << AVR32_USART_MR_MODE_OFFSET);

	/* Set protected register to previous value. */
	if(_wpen == true) {
		uart_set_access_protected_register(_uart);
	}

	/* Enable USART interrupt sources (but not Tx for now). */
	_uart->ier = AVR32_USART_IER_RXRDY_MASK | AVR32_USART_IER_TIMEOUT_MASK;

	/* Setup complete; enable communication.
	 Enable only output as input is not possible in synchronous mode without
	 transferring clock. */
	_uart->cr = AVR32_USART_CR_RXEN_MASK;

	return UART_STATUS_OK;
}


static void uart_set_rx_timeout(volatile avr32_usart_t *_uart, uint32_t _timeout)
{
	
	bool _wpen;
	
	/* Get access register if it is protected. */
	_wpen = uart_get_access_protected_register(_uart);
	_uart->rtor = _timeout;
	
	/* Set protected register to previous value. */
	if(_wpen == true) {
		uart_set_access_protected_register(_uart);
	}	
}


static void uart_set_mode_normal(volatile avr32_usart_t *_uart)
{
	bool _wpen;
	
	/* Get access control of protected register. */
	_wpen = uart_get_access_protected_register(_uart);
	
	_uart->mr = (_uart->mr & ~AVR32_USART_MR_MODE_MASK) | (AVR32_USART_MR_MODE_NORMAL << AVR32_USART_MR_MODE_OFFSET);
	
	/* Set protected register to previous value. */
	if(_wpen == true) {
		uart_set_access_protected_register(_uart);
	}
}


static void uart_set_mode_rs485(volatile avr32_usart_t *_uart)
{
	bool _wpen;
	
	/* Get access control of protected register. */
	_wpen = uart_get_access_protected_register(_uart);	

	_uart->mr = (_uart->mr & ~AVR32_USART_MR_MODE_MASK) | (AVR32_USART_MR_MODE_RS485 << AVR32_USART_MR_MODE_OFFSET);
	
	/* Set protected register to previous value. */
	if(_wpen == true) {
		uart_set_access_protected_register(_uart);
	}
}


static uart_status_code_t uart_reset(volatile avr32_usart_t *_uart)
{
	bool _wpen;
	bool global_interrupt_enabled = cpu_irq_is_enabled();

	if(_uart == NULL) return UART_ERR_INVALID_ARG;

	/* Disable all USART interrupts.
	Interrupts needed should be set explicitly on every reset. */
	if (global_interrupt_enabled) cpu_irq_disable();
	_uart->idr = 0xFFFFFFFF;
	_uart->csr;
	if (global_interrupt_enabled) cpu_irq_enable();

	/* Get access control of protected register. */
	_wpen = uart_get_access_protected_register(_uart);
	
	/* Reset mode and other registers that could cause unpredictable behavior after reset. */
	_uart->mr = 0;
	_uart->rtor = 0;
	_uart->ttgr = 0;
	
	/* Set protected register to previous value. */
	if(_wpen == true) {
		uart_set_access_protected_register(_uart);
	}

	/* Shutdown TX and RX (will be re-enabled when setup has successfully completed). */
	_uart->cr = AVR32_USART_CR_RSTRX_MASK   | AVR32_USART_CR_RSTTX_MASK		|
				AVR32_USART_CR_RSTSTA_MASK  | AVR32_USART_CR_RSTIT_MASK		|
				AVR32_USART_CR_RSTNACK_MASK | AVR32_USART_CR_RXDIS_MASK		|
				AVR32_USART_CR_TXDIS_MASK	| AVR32_USART_CR_RTSEN_MASK;

	return UART_STATUS_OK;
}


static void uart_setup(uint8_t _idx, uart_options_t *_opt)
{
	switch(_idx) {
		case serCOM1:
		case serCOM2:
			uart_init_rs232(uart1_inst, _opt, FPBC_HZ);
			uart_set_mode_normal(uart1_inst);
		break;

		case serCOM3:
		case serCOM4:
			aw_opts.mode = AWIRE_MODE_TRANSMIT;
			aw_opts.baudrate = _opt->baudrate;
			uart_init_rs232(uart3_inst, _opt, FPBA_HZ);
			uart_set_mode_normal(uart3_inst);
			awire_init(awire_inst, &aw_opts);
		break;

		case serCOM5:
		case serCOM6:
		case serTTL:
			uart_init_rs232(uart2_inst, _opt, FPBA_HZ);
			uart_set_mode_normal(uart2_inst);
		break;

		case serCOM7:
		case serCOM8:
			uart_init_rs232(uart4_inst, _opt, FPBC_HZ);
			uart_set_mode_normal(uart4_inst);
		break;

		case serRS485:
			uart_init_rs232(uart2_inst, _opt, FPBA_HZ);
			uart_set_mode_rs485(uart2_inst);
		break;

		default: break;
	}
}


//--------------------------------------- Public function -----------------------------------------------

com_descriptor_t uart_open(COM_path _path_name, const uint8_t _flag)
{
	uint8_t _com_path = 0, i;
	bool _open_status = false;
	
	i = 0;
	while(i < 10) {
		if(!strncmp(_path_name, com_port_name[i], 6)) {
			_com_path = i;
			i = 15;
		}
		i++;
	}

	/* Path name is invalid. */
	if(i < 15) return NULL;

	uart_peripheral_desc[_com_path].path_index = _com_path;
	uart_peripheral_desc[_com_path].port_state = 1;

	/* Open without transferring data. */
	if(_flag == 3) {
		return (void *)&uart_peripheral_desc[_com_path];
	}

	switch(_com_path) {
		case serCOM1:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART1Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART1Semaphore, (portTickType)20)) {
				uart_ctrl_channel &= ~(1 << CTRL1_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask &= ~(1 << CTRL1_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		case serCOM2:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART1Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART1Semaphore, (portTickType)20)) {
				uart_ctrl_channel |= (1 << CTRL1_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask |= (1 << CTRL1_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		case serCOM3:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART3Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART3Semaphore, (portTickType)20)) {
				uart_ctrl_channel &= ~(1 << CTRL3_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask &= ~(1 << CTRL3_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		case serCOM4:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART3Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART3Semaphore, (portTickType)20)) {
				uart_ctrl_channel |= (1 << CTRL3_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask |= (1 << CTRL3_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		case serTTL:
		case serRS485:
		case serCOM5:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART2Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART2Semaphore, (portTickType)20)) {
				uart_ctrl_channel &= ~(1 << CTRL2_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask &= ~(1 << CTRL2_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		case serCOM6:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART2Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART2Semaphore, (portTickType)20)) {
				uart_ctrl_channel |= (1 << CTRL2_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask |= (1 << CTRL2_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		case serCOM7:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART4Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART4Semaphore, (portTickType)20)) {
				uart_ctrl_channel &= ~(1 << CTRL4_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask &= ~(1 << CTRL4_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		case serCOM8:
			/* Force close. */
			if(_flag == 2) {
				xSemaphoreGive(xUART4Semaphore);
			}
			if(pdTRUE == xSemaphoreTake(xUART4Semaphore, (portTickType)20)) {
				uart_ctrl_channel |= (1 << CTRL4_OFFSET);
				/* Make it default channel. */
				if(_flag == 1) {
					uart_default_channel_mask |= (1 << CTRL4_OFFSET);
				}
				_open_status = true;
			}
		break;
		
		default: break;
	}
	
	if(_open_status == false) {
		return NULL;
	}

	while(SPI_STATUS_OK != spi_select_chip(spi_uart_desc));
	spi_write_byte(spi_uart_desc, (const void *)&uart_ctrl_channel, 1);
	while(SPI_STATUS_OK != spi_deselect_chip(spi_uart_desc));
	
	delay_ms(1);

	return (void *)&uart_peripheral_desc[_com_path];
}


uart_status_code_t uart_close(com_descriptor_t _descriptor, const uint8_t _flag)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	_uart_desc->port_state = 0;

	/* Closing without any data. */
	if(_flag == 3) return UART_STATUS_OK;

	switch(_uart_desc->path_index) {
		case serCOM1:
		case serCOM2:
			if((uart_default_channel_mask & (1 << CTRL1_OFFSET))
					^ (uart_ctrl_channel & (1 << CTRL1_OFFSET))) {

				uart_ctrl_channel |= ~uart_ctrl_channel & (1 << CTRL1_OFFSET);
			}

			if(_flag != 2) {
				while(pdFALSE == xSemaphoreTake(xUART1Semaphore, (portTickType)20));
			}
			xSemaphoreGive(xUART1Semaphore);
		break;
		
		case serCOM3:
		case serCOM4:
			if((uart_default_channel_mask & (1 << CTRL3_OFFSET))
					^ (uart_ctrl_channel & (1 << CTRL3_OFFSET))) {

				uart_ctrl_channel |= ~uart_ctrl_channel & (1 << CTRL3_OFFSET);
			}

			if(_flag != 2) {
				while(pdFALSE == xSemaphoreTake(xUART3Semaphore, (portTickType)20));
			}
			xSemaphoreGive(xUART3Semaphore);
		break;
		
		case serCOM5:
		case serCOM6:
		case serRS485:
		case serTTL:
			if((uart_default_channel_mask & (1 << CTRL2_OFFSET))
					^ (uart_ctrl_channel & (1 << CTRL2_OFFSET))) {

				uart_ctrl_channel |= ~uart_ctrl_channel & (1 << CTRL2_OFFSET);
			}

			if(_flag != 2) {
				while(pdFALSE == xSemaphoreTake(xUART2Semaphore, (portTickType)20));
			}
			xSemaphoreGive(xUART2Semaphore);
		break;
		
		case serCOM7:
		case serCOM8:
			if((uart_default_channel_mask & (1 << CTRL4_OFFSET))
					^ (uart_ctrl_channel & (1 << CTRL4_OFFSET))) {

				uart_ctrl_channel |= ~uart_ctrl_channel & (1 << CTRL4_OFFSET);
			}

			if(_flag != 2) {
				while(pdFALSE == xSemaphoreTake(xUART4Semaphore, (portTickType)20));
			}
			xSemaphoreGive(xUART4Semaphore);
		break;
		
		default: break;
	}

	/* Set port to default. */
	while(SPI_STATUS_OK != spi_select_chip(spi_uart_desc));
	spi_write_byte(spi_uart_desc, (const void *)&uart_ctrl_channel, 1);
	while(SPI_STATUS_OK != spi_deselect_chip(spi_uart_desc));

	delay_ms(1);

	return UART_STATUS_OK;
}


uart_status_code_t uart_write_word(com_descriptor_t _descriptor, const void *_pPacket, uint32_t _size_t)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_PORT_NOT_READY;
	}

	/* Protect unpredicted behavior if argument is NULL pointer */
	if(_pPacket == NULL) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_INVALID_ARG;
	}

	/* Start send data. */
	return uart_write_start(_uart_desc, _pPacket, _size_t, true);
}

uart_status_code_t uart_write_byte(com_descriptor_t _descriptor, const void *_pPacket, uint32_t _size_t)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_PORT_NOT_READY;
	}

	/* Protect unpredicted behavior if argument is NULL pointer */
	if(_pPacket == NULL) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_INVALID_ARG;
	}

	/* Start send data. */
	return uart_write_start(_uart_desc, _pPacket, _size_t, false);
}


uart_status_code_t uart_read_word(com_descriptor_t _descriptor, void *_pRxBuff, uint32_t _size_t)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_PORT_NOT_READY;
	}

	/* Protect unpredicted behavior if argument is NULL pointer */
	if(_pRxBuff == NULL) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_INVALID_ARG;
	}

	/* Start capturing data. */
	uart_read_start(_uart_desc, _pRxBuff, _size_t, true);

	return UART_STATUS_OK;
}


uart_status_code_t uart_read_byte(com_descriptor_t _descriptor, void *_pRxBuff, uint32_t _size_t)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_PORT_NOT_READY;
	}

	/* Protect unpredicted behavior if argument is NULL pointer */
	if(_pRxBuff == NULL) {
		uart_release_semaphore(_uart_desc->path_index);
		return UART_ERR_INVALID_ARG;
	}

	/* Start capturing data. */
	uart_read_start(_uart_desc, _pRxBuff, _size_t, false);

	return UART_STATUS_OK;
}


void uart_init(void)
{
	static const char _spi_uartctrl_port[] = "SPIUARTCTRL";

	spi_uart_desc = spi_open(_spi_uartctrl_port, 0);
	if(spi_uart_desc) {
		/* Initialize SPI interface for UART control port. */
		spi_setup(spi_uart_desc, &UART_CTRL_SPI_OPTIONS);
		/* Disable UART port. */
		gpio_set_pin_low(USART_CTRL_PIN_GPIO);

		/* Initialize UART option to default setting */
		_usart1_init();
		_usart2_init();
		_usart3_init();
		_usart4_init();
	}
}


uart_status_code_t uart_tranfer_mode(com_descriptor_t _descriptor, uart_transfer_mode_flag_t _flag)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	switch(_flag) {
		case UART_POLLED_TX:
			_uart_desc->transfer_mode &= ~0x01;
		break;

		case UART_POLLED_RX:
			_uart_desc->transfer_mode &= ~0x02;
		break;

		case UART_INTERRUPT_TX:
			_uart_desc->transfer_mode |= 0x01;
		break;

		case UART_INTERRUPT_RX:
			_uart_desc->transfer_mode |= 0x02;
		break;

		default: break;
	}

	return UART_STATUS_OK;
}


uart_status_code_t uart_rx_timeout(com_descriptor_t _descriptor, const uint32_t _to_ms)
{
	uint32_t _timeout_div = 1;
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	if(_to_ms) {
		if(_to_ms <= 1000) {
			_timeout_div = 1000 / _to_ms;
			receive_timeout[_uart_desc->path_index] = uart_opts[_uart_desc->path_index].baudrate / _timeout_div;
		}
		else {
			receive_timeout[_uart_desc->path_index] = (uart_opts[_uart_desc->path_index].baudrate * _to_ms) / 1000;
		}
	}

	return UART_STATUS_OK;
}


uart_status_code_t uart_load_setting(com_descriptor_t _descriptor)
{
	uint8_t *_ptrBase = ROM_Base_Block1, *_ptrUART;
	void *_p = NULL;
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	switch(_uart_desc->path_index) {
		case serCOM1:
			_p = _ptrBase + ROM_COM1_SETTING_OFFSET;
		break;

		case serCOM2:
			_p = _ptrBase + ROM_COM2_SETTING_OFFSET;
		break;

		case serCOM3:
			_p = _ptrBase + ROM_COM3_SETTING_OFFSET;
		break;

		case serCOM4:
			_p = _ptrBase + ROM_COM4_SETTING_OFFSET;
		break;

		case serCOM5:
			_p = _ptrBase + ROM_COM5_SETTING_OFFSET;
		break;

		case serCOM6:
			_p = _ptrBase + ROM_COM6_SETTING_OFFSET;
		break;

		case serCOM7:
			_p = _ptrBase + ROM_COM7_SETTING_OFFSET;
		break;

		case serCOM8:
			_p = _ptrBase + ROM_COM8_SETTING_OFFSET;
		break;

		case serRS485:
			_p = _ptrBase + ROM_RS485_SETTING_OFFSET;
		break;

		case serTTL:
			_p = _ptrBase + ROM_TTL_SETTING_OFFSET;
		break;

		default: break;
	}

	if(_p == NULL) {
		return UART_ERR_INVALID_ARG;
	}

	_ptrUART = _p;

	_p = _ptrUART + ROM_COM_BAUDRATE_OFFSET;
	uart_opts[_uart_desc->path_index].baudrate = BigEndian_LoadDWord(_p);
	_p = _ptrUART + ROM_COM_DATALENGTH_OFFSET;
	uart_opts[_uart_desc->path_index].charlength = BigEndian_LoadByte(_p);
	_p = _ptrUART + ROM_COM_PARITY_OFFSET;
	uart_opts[_uart_desc->path_index].paritytype = BigEndian_LoadByte(_p);
	_p = _ptrUART + ROM_COM_STOPBIT_OFFSET;
	uart_opts[_uart_desc->path_index].stopbits = BigEndian_LoadWord(_p);

	uart_setup(_uart_desc->path_index, &uart_opts[_uart_desc->path_index]);

	return UART_STATUS_OK;
}


bool uart_test_signal(com_descriptor_t _descriptor)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;
	bool _retval = false;

	if(_descriptor == NULL) return _retval;
	if(_uart_desc->path_index >= 10) return _retval;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return _retval;

	switch(_uart_desc->path_index) {
		case serCOM1:
		case serCOM2:
			if(pdTRUE == xSemaphoreTake(xUART1Signaling, (portTickType)5)) {
				_retval = true;
			}
		break;

		case serCOM3:
		case serCOM4:
			if(pdTRUE == xSemaphoreTake(xUART3Signaling, (portTickType)5)) {
				_retval = true;
			}
		break;

		case serCOM5:
		case serCOM6:
		case serRS485:
		case serTTL:
			if(pdTRUE == xSemaphoreTake(xUART2Signaling, (portTickType)5)) {
				_retval = true;
			}
		break;

		case serCOM7:
		case serCOM8:
			if(pdTRUE == xSemaphoreTake(xUART4Signaling, (portTickType)5)) {
				_retval = true;
			}
		break;

		default: break;
	}

	return _retval;
}


uart_status_code_t uart_release_signal(com_descriptor_t _descriptor)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;
	uart_status_code_t _retval = UART_ERR_IO_ERROR;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	switch(_uart_desc->path_index) {
		case serCOM1:
		case serCOM2:
			xSemaphoreGive(xUART1Signaling);
			_retval = UART_STATUS_OK;
		break;

		case serCOM3:
		case serCOM4:
			xSemaphoreGive(xUART3Signaling);
			_retval = UART_STATUS_OK;
		break;

		case serCOM5:
		case serCOM6:
		case serRS485:
		case serTTL:
			xSemaphoreGive(xUART2Signaling);
			_retval = UART_STATUS_OK;
		break;

		case serCOM7:
		case serCOM8:
			xSemaphoreGive(xUART4Signaling);
			_retval = UART_STATUS_OK;
		break;

		default: break;
	}

	return _retval;
}


uart_status_code_t uart_set_default(com_descriptor_t _descriptor)
{
	uint8_t *_ptrBase = ROM_Base_Block1, *_ptrUART;
	void *_p = NULL;
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	uart_opts[_uart_desc->path_index].baudrate = UART_SPEED_DEFAULT;
	uart_opts[_uart_desc->path_index].charlength = UART_DATA_BITS_DEFAULT;
	uart_opts[_uart_desc->path_index].paritytype = UART_PARITY_DEFAULT;
	uart_opts[_uart_desc->path_index].stopbits = UART_STOPBIT_DEFAULT;
	uart_opts[_uart_desc->path_index].channelmode = UART_CH_MODE_DEFAULT;

	switch(_uart_desc->path_index) {
		case serCOM1:
			_p = _ptrBase + ROM_COM1_SETTING_OFFSET;
		break;

		case serCOM2:
			_p = _ptrBase + ROM_COM2_SETTING_OFFSET;
		break;

		case serCOM3:
			_p = _ptrBase + ROM_COM3_SETTING_OFFSET;
		break;

		case serCOM4:
			_p = _ptrBase + ROM_COM4_SETTING_OFFSET;
		break;

		case serCOM5:
			_p = _ptrBase + ROM_COM5_SETTING_OFFSET;
		break;

		case serCOM6:
			_p = _ptrBase + ROM_COM6_SETTING_OFFSET;
		break;

		case serCOM7:
			_p = _ptrBase + ROM_COM7_SETTING_OFFSET;
		break;

		case serCOM8:
			_p = _ptrBase + ROM_COM8_SETTING_OFFSET;
		break;

		case serRS485:
			_p = _ptrBase + ROM_RS485_SETTING_OFFSET;
		break;

		case serTTL:
			_p = _ptrBase + ROM_TTL_SETTING_OFFSET;
		break;

		default: break;
	}

	if(_p == NULL) {
		return UART_ERR_INVALID_ARG;
	}

	_ptrUART = _p;
	_p = _ptrUART + ROM_COM_BAUDRATE_OFFSET;
	BigEndian_StoreDWord(_p, uart_opts[_uart_desc->path_index].baudrate);
	_p = _ptrUART + ROM_COM_DATALENGTH_OFFSET;
	BigEndian_StoreByte(_p, uart_opts[_uart_desc->path_index].charlength);
	_p = _ptrUART + ROM_COM_PARITY_OFFSET;
	BigEndian_StoreByte(_p, uart_opts[_uart_desc->path_index].paritytype);
	_p = _ptrUART + ROM_COM_STOPBIT_OFFSET;
	BigEndian_StoreWord(_p, uart_opts[_uart_desc->path_index].stopbits);

	uart_setup(_uart_desc->path_index, &uart_opts[_uart_desc->path_index]);

	return UART_STATUS_OK;
}


void uart_save_setting(void)
{
	/* Erase ROM Block. */
	vEraseROM(ROM_BASE_ADDR_BLOK1);
	/* Write ROM Block. */
	vWriteROM(ROM_BASE_ADDR_BLOK1, (const void *)ROM_Base_Block1, ROM_BLOCK_SIZE);
}


uart_status_code_t uart_set_speed(com_descriptor_t _descriptor, uint32_t _baud)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;
	uint8_t *_ptrBase = ROM_Base_Block1, *_ptrUART;
	void *_p = NULL;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	uart_opts[_uart_desc->path_index].baudrate = _baud;

	switch(_uart_desc->path_index) {
		case serCOM1:
			_p = _ptrBase + ROM_COM1_SETTING_OFFSET;
		break;

		case serCOM2:
			_p = _ptrBase + ROM_COM2_SETTING_OFFSET;
		break;

		case serCOM3:
			_p = _ptrBase + ROM_COM3_SETTING_OFFSET;
		break;

		case serCOM4:
			_p = _ptrBase + ROM_COM4_SETTING_OFFSET;
		break;

		case serCOM5:
			_p = _ptrBase + ROM_COM5_SETTING_OFFSET;
		break;

		case serCOM6:
			_p = _ptrBase + ROM_COM6_SETTING_OFFSET;
		break;

		case serCOM7:
			_p = _ptrBase + ROM_COM7_SETTING_OFFSET;
		break;

		case serCOM8:
			_p = _ptrBase + ROM_COM8_SETTING_OFFSET;
		break;

		case serRS485:
			_p = _ptrBase + ROM_RS485_SETTING_OFFSET;
		break;

		case serTTL:
			_p = _ptrBase + ROM_TTL_SETTING_OFFSET;
		break;

		default: break;
	}

	if(_p == NULL) {
		return UART_ERR_INVALID_ARG;
	}

	_ptrUART = _p;
	_p = _ptrUART + ROM_COM_BAUDRATE_OFFSET;
	BigEndian_StoreDWord(_p, uart_opts[_uart_desc->path_index].baudrate);

	uart_setup(_uart_desc->path_index, &uart_opts[_uart_desc->path_index]);

	return UART_STATUS_OK;
}


uart_status_code_t uart_set_databit(com_descriptor_t _descriptor, uint8_t _databit)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;
	uint8_t *_ptrBase = ROM_Base_Block1, *_ptrUART;
	void *_p = NULL;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	uart_opts[_uart_desc->path_index].charlength = _databit;

	switch(_uart_desc->path_index) {
		case serCOM1:
			_p = _ptrBase + ROM_COM1_SETTING_OFFSET;
		break;

		case serCOM2:
			_p = _ptrBase + ROM_COM2_SETTING_OFFSET;
		break;

		case serCOM3:
			_p = _ptrBase + ROM_COM3_SETTING_OFFSET;
		break;

		case serCOM4:
			_p = _ptrBase + ROM_COM4_SETTING_OFFSET;
		break;

		case serCOM5:
			_p = _ptrBase + ROM_COM5_SETTING_OFFSET;
		break;

		case serCOM6:
			_p = _ptrBase + ROM_COM6_SETTING_OFFSET;
		break;

		case serCOM7:
			_p = _ptrBase + ROM_COM7_SETTING_OFFSET;
		break;

		case serCOM8:
			_p = _ptrBase + ROM_COM8_SETTING_OFFSET;
		break;

		case serRS485:
			_p = _ptrBase + ROM_RS485_SETTING_OFFSET;
		break;

		case serTTL:
			_p = _ptrBase + ROM_TTL_SETTING_OFFSET;
		break;

		default: break;
	}

	if(_p == NULL) {
		return UART_ERR_INVALID_ARG;
	}

	_ptrUART = _p;
	_p = _ptrUART + ROM_COM_DATALENGTH_OFFSET;
	BigEndian_StoreByte(_p, uart_opts[_uart_desc->path_index].charlength);

	uart_setup(_uart_desc->path_index, &uart_opts[_uart_desc->path_index]);

	return UART_STATUS_OK;
}


uart_status_code_t uart_set_parity(com_descriptor_t _descriptor, uint8_t _par)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;
	uint8_t *_ptrBase = ROM_Base_Block1, *_ptrUART;
	void *_p = NULL;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	uart_opts[_uart_desc->path_index].paritytype = _par;

	switch(_uart_desc->path_index) {
		case serCOM1:
			_p = _ptrBase + ROM_COM1_SETTING_OFFSET;
		break;

		case serCOM2:
			_p = _ptrBase + ROM_COM2_SETTING_OFFSET;
		break;

		case serCOM3:
			_p = _ptrBase + ROM_COM3_SETTING_OFFSET;
		break;

		case serCOM4:
			_p = _ptrBase + ROM_COM4_SETTING_OFFSET;
		break;

		case serCOM5:
			_p = _ptrBase + ROM_COM5_SETTING_OFFSET;
		break;

		case serCOM6:
			_p = _ptrBase + ROM_COM6_SETTING_OFFSET;
		break;

		case serCOM7:
			_p = _ptrBase + ROM_COM7_SETTING_OFFSET;
		break;

		case serCOM8:
			_p = _ptrBase + ROM_COM8_SETTING_OFFSET;
		break;

		case serRS485:
			_p = _ptrBase + ROM_RS485_SETTING_OFFSET;
		break;

		case serTTL:
			_p = _ptrBase + ROM_TTL_SETTING_OFFSET;
		break;

		default: break;
	}

	if(_p == NULL) {
		return UART_ERR_INVALID_ARG;
	}

	_ptrUART = _p;
	_p = _ptrUART + ROM_COM_PARITY_OFFSET;
	BigEndian_StoreByte(_p, uart_opts[_uart_desc->path_index].paritytype);

	uart_setup(_uart_desc->path_index, &uart_opts[_uart_desc->path_index]);

	return UART_STATUS_OK;
}


uart_status_code_t uart_set_stopbit(com_descriptor_t _descriptor, uint8_t _stop)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;
	uint8_t *_ptrBase = ROM_Base_Block1, *_ptrUART;
	void *_p = NULL;

	if(_descriptor == NULL) return UART_ERR_IO_ERROR;
	if(_uart_desc->path_index >= 10) return UART_ERR_IO_ERROR;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return UART_ERR_PORT_NOT_READY;

	uart_opts[_uart_desc->path_index].stopbits = _stop;

	switch(_uart_desc->path_index) {
		case serCOM1:
			_p = _ptrBase + ROM_COM1_SETTING_OFFSET;
		break;

		case serCOM2:
			_p = _ptrBase + ROM_COM2_SETTING_OFFSET;
		break;

		case serCOM3:
			_p = _ptrBase + ROM_COM3_SETTING_OFFSET;
		break;

		case serCOM4:
			_p = _ptrBase + ROM_COM4_SETTING_OFFSET;
		break;

		case serCOM5:
			_p = _ptrBase + ROM_COM5_SETTING_OFFSET;
		break;

		case serCOM6:
			_p = _ptrBase + ROM_COM6_SETTING_OFFSET;
		break;

		case serCOM7:
			_p = _ptrBase + ROM_COM7_SETTING_OFFSET;
		break;

		case serCOM8:
			_p = _ptrBase + ROM_COM8_SETTING_OFFSET;
		break;

		case serRS485:
			_p = _ptrBase + ROM_RS485_SETTING_OFFSET;
		break;

		case serTTL:
			_p = _ptrBase + ROM_TTL_SETTING_OFFSET;
		break;

		default: break;
	}

	if(_p == NULL) {
		return UART_ERR_INVALID_ARG;
	}

	_ptrUART = _p;
	_p = _ptrUART + ROM_COM_STOPBIT_OFFSET;
	BigEndian_StoreWord(_p, uart_opts[_uart_desc->path_index].stopbits);

	uart_setup(_uart_desc->path_index, &uart_opts[_uart_desc->path_index]);

	return UART_STATUS_OK;
}


uart_options_t *uart_get_setting(com_descriptor_t _descriptor)
{
	uart_peripheral_descriptors_t *_uart_desc = _descriptor;

	if(_descriptor == NULL) return NULL;
	if(_uart_desc->path_index >= 10) return NULL;

	/* Port has not opened yet. */
	if(_uart_desc->port_state != 1) return NULL;

	return &uart_opts[_uart_desc->path_index];
}


#endif /* BOARD_1_0_USED */
